package com.server.questionbank.snframe.service.CourseService.Impl;

import com.server.questionbank.snframe.domain.Course.*;
import com.server.questionbank.snframe.domain.Course.Result.CourseFigures;
import com.server.questionbank.snframe.domain.Course.Type.CourseLabel;
import com.server.questionbank.snframe.domain.Course.Type.CourseType;
import com.server.questionbank.snframe.domain.ResDTO.PageResult;
import com.server.questionbank.snframe.domain.ResDTO.SearchResult;
import com.server.questionbank.snframe.domain.TInterest;
import com.server.questionbank.snframe.domain.User.TUser;
import com.server.questionbank.snframe.mapper.Course.*;
import com.server.questionbank.snframe.mapper.Course.Resource.CourseFilesMapper;
import com.server.questionbank.snframe.mapper.Course.Type.CourseDifficultyMapper;
import com.server.questionbank.snframe.mapper.Course.Type.CourseLabelMapper;
import com.server.questionbank.snframe.mapper.Course.Type.CourseTypeMapper;
import com.server.questionbank.snframe.service.CourseService.*;
import com.server.questionbank.snframe.service.CourseService.Member.CusMemberGroupService;
import com.server.questionbank.snframe.service.OllamaService.KnowledgeBaseService.TextEmbeddingService.TextEmbeddingService;
import com.server.questionbank.snframe.service.UsersService.TInterestService;
import com.server.questionbank.snframe.service.UsersService.UsersService;
import com.server.questionbank.snframe.util.AvatarProcessing;
import com.server.questionbank.snframe.util.MinIo.MinIoBucket;
import com.server.questionbank.snframe.util.MinIo.MinIoFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
public class TCourseServiceImpl implements TCourseService {
    @Autowired // 课程映射器
    private TCourseMapper tCourseMapper;
    @Autowired // 文件服务
    private MinIoFactory minIoFactory;
    @Autowired // 课程难度映射器
    private CourseDifficultyMapper courseDifficultyMapper;
    @Autowired // 课程类型映射
    private CourseTypeMapper courseTypeMapper;
    @Autowired // 课程标签映射
    private CourseLabelMapper courseLabelMapper;
    @Autowired // 课程学生分组服务
    private CusMemberGroupService cusStudyGroupService;
    @Autowired // 用户服务
    private UsersService usersService;
    @Autowired // 兴趣服务
    private TInterestService tInterestService;
    @Autowired // 文本嵌入服务（使用分词器）
    private TextEmbeddingService textEmbeddingService;


    @Autowired // 课程文件映射器
    CourseFilesMapper courseFilesMapper;

    // 获取所有课程
    @Override
    public List<TCourse> getAllCourse() {
        return tCourseMapper.getAllCourse();
    }

    // 获取课程信息
    @Override
    public TCourse getCourseById(Long courseId) {
        return tCourseMapper.getCourseById(courseId);
    }

    // 获取课程类型
    @Override
    public List<CourseType> getCourseType(Long courseId) {
        return courseTypeMapper.getCourseTypeByClassId(courseId);
    }

    // 获取课程标签
    @Override
    public List<CourseLabel> getCourseLabel(Long courseId) {
        return courseLabelMapper.getCourseLabelByClassId(courseId);
    }

    // 设置课程介绍
    @Override
    public boolean setCourseIntroduce(Long courseId, String courseIntroduce) {
        return tCourseMapper.setCourseIntroduce(courseId, courseIntroduce) > 0;
    }

    // 获取课程介绍
    @Override
    public String getCourseIntroduce(Long courseId) {
        return tCourseMapper.getCourseIntroduce(courseId);
    }

    // 创建课程
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false)
    public boolean createCourse(TCourse course, String coverData, List<Long> courseType, List<Long> courseLabel) throws Exception {
        // 插入课程
        tCourseMapper.insertCourse(course);

        // 上传封面
        updateCover(course.getCourseId(), coverData);

        // 插入课程类型
        for (Long typeId : courseType) {
            tCourseMapper.insertCourseType(typeId, course.getCourseId());
        }

        // 插入课程标签
        for (Long labelId : courseLabel) {
            tCourseMapper.insertCourseLabel(labelId,course.getCourseId());
        }

        // 创建默认分组
        cusStudyGroupService.createCusStudyGroup(course.getCourseId(), null);

        return true;
    }

    // 修改用户头像
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false)
    public void updateCover(Long courseId, String coverData) {
        if (coverData == null || coverData.isBlank()) {
            throw new IllegalArgumentException("❌ coverData 不能为空");
        }
        if (courseId == null || courseId <= 0) {
            throw new IllegalArgumentException("❌ courseId 不正确");
        }
        try {
            MinIoBucket minIoBucket = minIoFactory.openBucket("course", true);

            // 解析头像类型和数据
            Pattern pattern = Pattern.compile("data:(image/\\w+);base64,");
            Matcher matcher = pattern.matcher(coverData);
            String coverName = "";
            if (matcher.find())
            {
                // 处理封面
                try
                {
                    coverData = AvatarProcessing.AvatarProcessing(coverData, 300, 150);
                } catch (Exception e){ throw new RuntimeException("封面处理失败", e); }

                if (coverData == null) throw new RuntimeException("封面处理失败");

                // 判断历史头像
                List<String> files = minIoBucket.listFiles(courseId + "/cover/");
                coverName = "cover_" + String.valueOf(files.size()) + ".png";
                // 删除最古老的头像
                if (files.size() >= 5)
                {
                    String oldest = files.get(0);
                    minIoBucket.deleteFile(oldest);
                    coverName = MinIoBucket.getFileName(oldest); // 只取文件名（avatar_X.png）
                }

                // 解码Base64数据
                int commaIndex = coverData.indexOf(",");
                byte[] fileBytes = Base64.getDecoder().decode(coverData.substring(commaIndex + 1));
                InputStream fileInputStream = new ByteArrayInputStream(fileBytes);

                // 设置封面
                tCourseMapper.setCover(courseId, coverName);

                // 上传新头像
                minIoBucket.uploadFile(courseId + "/cover/" + coverName, fileInputStream, "image/png", 0);
            }
            else
            {
                // 判断历史头像是否存在
                if (!minIoBucket.fileExists(courseId + "/cover/" + coverName))
                    throw new IllegalArgumentException("封面格式不正确"); // 历史头像不存在，并且格式不正确 抛出异常
                coverName = coverData;

                // 设置封面
                tCourseMapper.setCover(courseId, coverName);
            }

        } catch (Exception e) {
            throw new RuntimeException("上传文件失败", e);
        }
    }

    // 查询热门课程
    @Override
    public List<CourseFigures> getHotCourse() {
        return findCourseByConditions(
                null, null, null, null, null, null, null, null,
                1L, 36L, 0.7, 0.2, 0.1, false
        ).getData().getList();
    }

    // 查询课程
    @Override
    public SearchResult<PageResult<CourseFigures>> findCourseByConditions(
            Long courseId, Long memberId, Long teacherId, String search,
            Long difficultyId, List<Long> type, List<Long> label, List<Long> excludeCourseIdList,
            Long pageNum, Long pageSize, Double figureWeight, Double userLikeWeight, Double timeWeight, Boolean explore) {
        if (pageNum == null || pageNum <= 0) pageNum = 1L;
        if (pageSize == null || pageSize <= 0) pageSize = 1L;
        pageSize = Math.min(pageSize, 1000L);
        Long offset = pageSize * (pageNum - 1L);

        TUser user = usersService.getLoginUser();

        try {
            List<String> searchList = null;
            List<TInterest> learningRecordTypeList = null;
            List<TInterest> learningRecordLabelList = null;
            List<TInterest> chooseTypeList = null;
            List<TInterest> chooseLabelList = null;
            List<TInterest> joinTypeList = null;
            List<TInterest> joinLabelList = null;
            List<TInterest> collectTypeList = null;
            List<TInterest> collectLabelList = null;
            List<TInterest> createTypeList = null;
            List<TInterest> createLabelList = null;
            if (search != null && !search.isEmpty())
            {
                System.out.println(search);
                searchList = new ArrayList<>(textEmbeddingService.extractKeywords(search));
                if (searchList.size() != 1) searchList.add(search); // 如果关键词数量只有一个则不添加搜索词
                System.out.println(searchList);
            }
            if (user != null && user.getUserId() != null)
            {
                // 获取用户选择的课程类型和标签
//                chooseTypeList = courseTypeMapper.getCourseTypeByChooseUserId(user.getUserId()).stream().map(CourseType::getTypeId).toList();
//                chooseLabelList = courseLabelMapper.getCourseLabelByChooseUserId(user.getUserId()).stream().map(CourseLabel::getLabelId).toList();
                // 获取用户加入的课程类型和标签
                joinTypeList = tInterestService.getCourseTypeByJoinUserId(user.getUserId());
                joinLabelList = tInterestService.getCourseLabelByJoinUserId(user.getUserId());
                // 获取用户收藏的课程类型和标签
                collectTypeList = tInterestService.getCourseTypeByCollectUserId(user.getUserId());
                collectLabelList = tInterestService.getCourseLabelByCollectUserId(user.getUserId());
                // 获取用户创建的课程类型和标签
                createTypeList = tInterestService.getCourseTypeByCreateUserId(user.getUserId());
                createLabelList = tInterestService.getCourseLabelByCreateUserId(user.getUserId());
            }
            return new SearchResult<>(new PageResult<>(
                    tCourseMapper.findCourseByWeight(
                            courseId, memberId, teacherId, searchList, difficultyId, type, label,
                            learningRecordTypeList, learningRecordLabelList, // 学习记录
                            joinTypeList, joinLabelList,  // 加入记录
                            collectTypeList, collectLabelList, // 收藏记录
                            createTypeList, createLabelList,  // 创建记录
                            chooseTypeList, chooseLabelList, // 学习记录
                            excludeCourseIdList,
                            offset, pageSize, // 分页
                            figureWeight, // 数据得分权重
                            userLikeWeight,  // 用户喜好权重
                            timeWeight, // 时间权重 (更新权重)
                            explore, // 是否启用探索
                            0.01, // 冷门探索权重
                            0.05, // 冷门探索概率
                            0.03,  // 随机探索权重
                            0.01   // 随机探索概率
                    ),
                    tCourseMapper.findCourseByCount(courseId, null, teacherId, null, searchList, difficultyId),
                    pageNum, pageSize
            ), searchList);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    // 查询课程
    @Override
    public SearchResult<PageResult<CourseFigures>> findCourseByConditions(Long courseId, Long teacherId, String search, Long difficultyId, List<Long> type, List<Long> label, List<Long> excludeCourseIdList, Long pageNum, Long pageSize, Boolean explore) {
        return findCourseByConditions(courseId, null, teacherId, search, difficultyId, type, label, excludeCourseIdList, pageNum, pageSize, null, null, null, explore);
    }

    // 获取推荐课程
    @Override
    public List<CourseFigures> getRecommendCourse(Long courseId, Long recommendCount) {
        try {
            if (courseId == null) return null;
            Double figureWeight = 0.5, userLikeWeight = 0.4, timeWeight = 0.1;
            // 获取课程类型和标签
            List<Long> courseTypeList = getCourseType(courseId).stream().map(CourseType::getTypeId).toList();
            List<Long> courseLabelList = getCourseLabel(courseId).stream().map(CourseLabel::getLabelId).toList();
            // 查询推荐课程（与本课程有相同成员的课程，即上过该课程的学生还加入了的课程）
            List<CourseFigures> recommendCourse = findCourseByConditions(
                    null, courseId, null, null, null, courseTypeList, courseLabelList, List.of(courseId),
                    1L, recommendCount, figureWeight, userLikeWeight, timeWeight, false
            ).getData().getList();
            // 如果推荐课程数量不足，则进行 课程内容相关性推荐，若还是不足则进行 用户喜好推荐
            if (recommendCourse == null || recommendCourse.size() < recommendCount)
            {
                // 获取已经推荐的数量
                Long recommendCountNum = recommendCourse == null ? 0L : recommendCourse.size();
                if (recommendCountNum < recommendCount)
                {
                    List<Long> excludeCourseIdList = new ArrayList<>();
                    if (recommendCourse != null) excludeCourseIdList.addAll(recommendCourse.stream().map(CourseFigures::getCourseId).toList());
                    excludeCourseIdList.add(courseId);
                    // 获取课程内容相关性推荐，数量不足自动填充 用户喜好推荐
                    List<CourseFigures> randomCourse = findCourseByConditions(
                            null, null, null, null, null, courseTypeList, courseLabelList, excludeCourseIdList,
                            1L, recommendCount - recommendCountNum, figureWeight, userLikeWeight, timeWeight, false
                    ).getData().getList();
                    if (randomCourse != null) recommendCourse.addAll(randomCourse);
                }
            }
            return recommendCourse;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}
